package com.zx.flow.core.execute;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zx.flow.api.config.FlowConfig;
import com.zx.flow.api.dict.FlowDict.Event;
import com.zx.flow.api.exception.FlowException;
import com.zx.flow.api.execute.model.FlowContext;
import com.zx.flow.api.execute.model.FlowNode;
import com.zx.flow.api.execute.request.FlowParam;
import com.zx.flow.api.execute.request.FlowParamListener;
import com.zx.flow.api.execute.request.manager.ManagerFlowConfigListForm;
import com.zx.flow.api.execute.request.manager.ManagerFlowListForm;
import com.zx.flow.api.execute.response.FlowResult;
import com.zx.flow.core.cache.FlowConfigCache;
import com.zx.flow.core.engine.FlowEngine;
import com.zx.flow.db.FlowStorageHandler;
import com.zx.flow.db.entity.FlowSecretEntity;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * 事件处理器
 *
 * @param <T>
 */
@Slf4j
@Data
public abstract class EventHandler<T extends FlowParam> implements FlowStorageHandler {

    private FlowEngine engine;

    /**
     * 事件触发后，判断是否符合条件
     *
     * @param flow
     * @param param
     * @return
     */
    public abstract boolean in(FlowContext flow, T param);

    /**
     * 对外发布时间事件
     *
     * @param engine
     * @param flow
     * @param param
     */
    public FlowResult publicEvent(FlowEngine engine, FlowContext flow, T param) {
        log.info("事件处理, event={}, param={}", param.getClass().getSimpleName(), param);
        this.engine = engine;
        try {
            if (this.in(flow, param)) {
                return this.on(flow, param);
            }
            // 不符合条件，状态为无效
            log.info("事件处理, 不符合条件, msg={}, event={}, param={}", param.getClass().getSimpleName(), param);
            return FlowResult.invalid("事件处理, 不符合条件, event=" + param.getClass().getSimpleName(), flow);
        } catch (FlowException e) {
            log.warn("事件处理, 执行失败, msg={}", e.getMessage());
            return FlowResult.fail(e.getMessage(), flow);
        } catch (Exception e) {
            log.error("事件处理, 执行异常", e);
            return FlowResult.exception(e.getMessage(), flow);
        }
    }


    /**
     * 本handler需要处理的事务
     *
     * @param flow
     * @param param
     * @return
     */
    public abstract FlowResult on(FlowContext flow, T param);

    /**
     * 获得参数的类型
     *
     * @return
     */
    public Class<T> paramType() {
        Type genType = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        return (Class<T>) params[0];
    }

    /**
     * 获得流程配置
     *
     * @param flowCode
     * @param flowId
     * @return
     */
    public FlowConfig getFlowConfig(String flowCode, String flowId) {
        return FlowConfigCache.getFlowConfig(flowCode, flowId);
    }

    /**
     * 触发监听
     *
     * @param node
     * @param event
     */
    public void listener(FlowNode node, Event event) {
        this.execute(new FlowParamListener(node, event));
    }

    public FlowResult execute(FlowParam param) {
        return this.getEngine().execute(param);
    }

    @Override
    public List<FlowSecretEntity> getSecret() {
        return this.engine.getStorageHandler().getSecret();
    }

    @Override
    public IPage<FlowContext> getFlowList(ManagerFlowListForm form) {
        return this.engine.getStorageHandler().getFlowList(form);
    }

    @Override
    public IPage<FlowConfig> getFlowConfigList(ManagerFlowConfigListForm form) {
        return this.engine.getStorageHandler().getFlowConfigList(form);
    }

    @Override
    public List<FlowConfig> getAllFlowConfig() {
        return this.engine.getStorageHandler().getAllFlowConfig();
    }

    @Override
    public void saveFlowConfig(FlowConfig flowConfig) {
        this.engine.getStorageHandler().saveFlowConfig(flowConfig);
    }

    @Override
    public void saveFlow(FlowContext flowContext) {
        this.engine.getStorageHandler().saveFlow(flowContext);
    }

    @Override
    public FlowContext getFlow(String flowId) {
        return this.engine.getStorageHandler().getFlow(flowId);
    }

    @Override
    public void saveNode(String flowId, FlowNode flowNode) {
        this.engine.getStorageHandler().saveNode(flowId, flowNode);
    }

    @Override
    public List<FlowNode> getNodes(String flowId) {
        return this.engine.getStorageHandler().getNodes(flowId);
    }

    @Override
    public FlowNode getNode(String flowId, String nodeId) {
        return this.engine.getStorageHandler().getNode(flowId, nodeId);
    }

}
